// SPDX-License-Identifier: GPL-2.0
/*
 * Author   : Ryan Shen
 * Contract :
 * File     : hi_drv_wdt.c
 * Describe : hisilicon watchdog driver.
 * Platform : ARM Cortex-A9 & Linux 2.6.34.10
 * Log      : 2013-01-23 : init version completed.
 *
 * Copyright (c) 2010-2012 by Hisilicon. All rights reserved.
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/notifier.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
#include <linux/spinlock_types.h>
#include <asm/io.h>
#include "include/mach/hi_drv_wdt.h"
#include "include/mach/hw_drv_core.h"

/*
 * Registers definition
 */
#define SD5115_WDT_CONFIG	(0x13f00038)
#define SD5116_WDT_CONFIG	(0x14880070)
#define SD5118_WDT_CONFIG	(0x14880070)
#define SD5610_WDT_CONFIG	(0x1488006c)
#define SD5182_WDT_CONFIG	(0x14880070)
#define SD1156_WDT_CONFIG	(0x1012800c)
#define SD5190_WDT_CONFIG	(0x1014A004)

#define SD5115_SC_PERCTRL42	(0x10100144)
#define SD5116_SC_PERCTRL42	(0x14880054)
#define SD5116T_SC_PERCTRL42	(0x14880050)
#define SD5118_SC_PERCTRL42	(0x14880050)
#define SD5610_SC_PERCTRL42	(0x14880054)
#define SD5182H_SC_PERCTRL42	(0x14880050)
#define SD5182S_SC_PERCTRL42	(0x14880040)
#define SD5182T_SC_PERCTRL42	(0x14880050)
#define SD1156H_SC_PERCTRL42	(0x10128004)
#define SD1156H_WDT_CONFIG	(0x18200230)
#define SD1156H_GLOBAL_RST	(0x1820027c)
#define SD5190_SC_PERCTRL42	(0x1014A014)
#define SD5190_SC_PERCTRL43	(0x1014A010)

#define WDT_RST_TIME_CFG_M		(0x7fC00)
#define WDT_RST_TIME_5117P_CFG_M	(0xffC00)
#define WDT_RST_TIME_5182H_CFG_M	(0xff8)
#define WDT_RST_TIME_5182S_CFG_M	(0x3ff)
#define WDT_RST_TIME_CFG_S		(10)
#define WDT_RST_TIME_CFG_S_5182H	(3)
#define WDT_RST_TIME_1156H_CFG_M	(0xf)
#define WDT_RST_TIME_5190_CFG_MSK	(0x7fC00)

#define SD5190_WDT_EN_REG		(0x1014A000)
#define SD5190_WDT_MAGIC		(0x5a5a0000)
#define SD5190_WDT_EN_BIT_INT_EN	(0x1 << 2)
#define SD5190_WDT_EN_BIT_RST_EN	(0x1 << 1)
#define SD5190_WDT_EN_BIT_EN		(0x1 << 0)

/*
 * Macro definition
 */
#define HI_WDT_PFX "hi_wdt: "

#define DEFAULT_TIMO	(300)
#define DEFAULT_AUTO_CLEAR_PERIOD	(270)

#define HI_WDT_PERIOD_MIN	(1)
#define HI_WDT_PERIOD_MAX	(300)

#define HI_WDT_CLEAR_OPT0	(0x55AA5A5A)
#define HI_WDT_CLEAR_OPT1	(0xAA55A5A5)
#define HI_WDT_CLEAR_OPT1_1156	(0x76)

/* watchdog register address of each chip */
#define HW_KER_WDG_ADDR_5116_8		(0x14880064)
#define HW_KER_WDG_ADDR_5115		(0x1010017C)
#define HW_KER_WDG_ADDR_5182S		(0x14880068)
#define HW_KER_WDG_ADDR_5116H		(0x10128000)

/* value to enable and disable watchdog for each chip */
#define HW_KER_WDG_CLOSE_VALUE1_5116	(0xABCD5116)
#define HW_KER_WDG_CLOSE_VALUE2_5116	(0xED574447)
#define HW_KER_WDG_OPEN_VALUE1_5116	(0x4F4E5452)
#define HW_KER_WDG_OPEN_VALUE2_5116	(0x12345116)

#define HW_KER_WDG_CLOSE_VALUE1_5118	(0xABCD5118)
#define HW_KER_WDG_CLOSE_VALUE2_5118	(0xED574447)
#define HW_KER_WDG_OPEN_VALUE1_5118	(0x4F4E5452)
#define HW_KER_WDG_OPEN_VALUE2_5118	(0x12345118)

#define HW_KER_WDG_CLOSE_VALUE1_5115	(0xABCD5115)
#define HW_KER_WDG_CLOSE_VALUE2_5115	(0xED574447)
#define HW_KER_WDG_OPEN_VALUE1_5115	(0x4F4E5452)
#define HW_KER_WDG_OPEN_VALUE2_5115	(0x12345115)

#define HW_KER_WDG_CLOSE_VALUE1_5610	(0xABCD5610)
#define HW_KER_WDG_CLOSE_VALUE2_5610	(0xED574447)
#define HW_KER_WDG_OPEN_VALUE1_5610	(0x4F4E5452)
#define HW_KER_WDG_OPEN_VALUE2_5610	(0x12345610)

#define KER_WDG_OPEN_1156		(1)
#define KER_WDG_CFG_1156_EN		(0x21)
#define CONFIG_WDT_CLOCK_KHZ_1156	(48000000)

#define HW_KER_WDG_DELAY	(10)

#define WTD_EN_CFG(en_chip, chip) do { \
	g_pui_WGT_EN = ioremap(HW_KER_WDG_ADDR_##en_chip, sizeof(uint32_t)); \
	gui_wdg_close_value1 = HW_KER_WDG_CLOSE_VALUE1_##chip; \
	gui_wdg_close_value2 = HW_KER_WDG_CLOSE_VALUE2_##chip; \
	gui_wdg_open_value1 = HW_KER_WDG_OPEN_VALUE1_##chip; \
	gui_wdg_open_value2 = HW_KER_WDG_OPEN_VALUE2_##chip; \
} while (0)

/*
 * global var
 */
/* wdt register remap */
static uint32_t *g_pui_WGT_CONFIG;
static uint32_t *g_pui_SC_PERCTRL42;
static uint32_t *g_pui_SC_PERCTRL43;
static uint32_t *g_1156_wdt_cfg;
static uint32_t *g_pui_WGT_EN;
static uint32_t *g_1156_global_reset;

/* wdt cfg en */
uint32_t gui_wdg_close_value1;
uint32_t gui_wdg_close_value2;
uint32_t gui_wdg_open_value1;
uint32_t gui_wdg_open_value2;

/* register reset hook function */
#ifdef CONFIG_RTOS_RESET_NOTIFIER
extern int register_reset_notifier(struct notifier_block *nb);
extern int unregister_reset_notifier(struct notifier_block *nb);
#else
static inline int register_reset_notifier(struct notifier_block *nb)
{
	return 0;
}

static inline int unregister_reset_notifier(struct notifier_block *nb)
{
	return 0;
}
#endif
struct notifier_block reset_nb;

extern enum HW_CHIP_ID_E hw_chip_id;

/* wdt attr */
static struct hi_wdt_attr_s hi_wdt_attr_log;
/* wdt timer */
static struct timer_list hi_wdt_timer;
/* wdt lock */
static DEFINE_SPINLOCK(hi_wdt_lock);
/* jiffies of last wdt clear */
static uint32_t hi_wdt_jiffies;
/* auto wdt param */
static int hi_wdt_auto;

#define WDT_NUM_TOPS		(16)
#define WDT_FIX_TOP(_idx)	(1U << (16 + _idx))

static const u32 g_wdt_fix_tops[WDT_NUM_TOPS] = {
	WDT_FIX_TOP(0),  WDT_FIX_TOP(1),  WDT_FIX_TOP(2),
	WDT_FIX_TOP(3),  WDT_FIX_TOP(4),  WDT_FIX_TOP(5),
	WDT_FIX_TOP(6),  WDT_FIX_TOP(7),  WDT_FIX_TOP(8),
	WDT_FIX_TOP(9),  WDT_FIX_TOP(10), WDT_FIX_TOP(11),
	WDT_FIX_TOP(12), WDT_FIX_TOP(13), WDT_FIX_TOP(14),
	WDT_FIX_TOP(15)
};

/*
 * private function
 */
static void hi_kernel_wdt_dump(void);
void hi_kernel_wdt_proc(void);

/*
 * function definition
 */

static void hi_watchdog_reset_sd5190(void)
{
	writel((SD5190_WDT_MAGIC | 0), g_pui_WGT_CONFIG);
	writel((SD5190_WDT_MAGIC | 1), g_pui_WGT_CONFIG);
}

static void hi_watchdog_en_sd5190(uint32_t en)
{
	uint32_t tmp = readl(g_pui_WGT_EN);

	if (en == 1)
		tmp |= (SD5190_WDT_EN_BIT_RST_EN | SD5190_WDT_EN_BIT_EN | SD5190_WDT_EN_BIT_INT_EN);
	else
		tmp &= ~(SD5190_WDT_EN_BIT_RST_EN | SD5190_WDT_EN_BIT_EN);

	writel((SD5190_WDT_MAGIC | tmp), g_pui_WGT_EN);
}

static uint32_t rst_time_cfg_1156(int period)
{
	uint32_t rst_time = WDT_NUM_TOPS;
	uint32_t idx;
	uint32_t timer_period = period * CONFIG_WDT_CLOCK_KHZ_1156;

	for (idx = 0; idx < WDT_NUM_TOPS; idx++) {
		if (g_wdt_fix_tops[idx] >= timer_period)
			break;
	}

	rst_time = idx;
	if (rst_time >= WDT_NUM_TOPS)
		rst_time--;

	/* restart and change the value of top to 8 */
	if (period == 1)
		rst_time = 8;

	return rst_time;
}

/* WDT chip reset */
void sd511x_wdt_reset(void)
{
	struct hi_wdt_attr_s st_attr;
	uint32_t ui_ret;
	uint32_t *pui_addr1 = NULL;

	pr_info("Wdt chip reset!!\n");

	memset(&st_attr, 0x0, sizeof(st_attr));

	ui_ret = hi_kernel_wdt_attr_get(&st_attr);
	if (ui_ret != 0)
		pr_err("Get wdt attr err\n");

	st_attr.em_mode = HI_WDT_USER_MODE_E;
	st_attr.ui_period = 1;

	ui_ret = hi_kernel_wdt_attr_set(&st_attr);
	if (ui_ret != 0)
		pr_err("Set wdt attr err\n");

	hi_kernel_wdt_proc();

	if (hw_chip_id == HW_CHIP_ID_5117V_E) {
		mdelay(1500);
		pui_addr1 = ioremap(0x14880000, sizeof(uint32_t));
		writel(0x51162100, pui_addr1);
		writel(0xAEE9DEFF, pui_addr1);
		iounmap(pui_addr1);
	} else if ((hw_chip_id == HAL_CHIP_ID_1156H) || (hw_chip_id == HAL_CHIP_ID_1155H) ||
		(hw_chip_id == HAL_CHIP_ID_1156E)) {
		mdelay(1500);
		pr_err("Global soft reset\n");
		writel(0x51162100, g_1156_global_reset);
		writel(0xAEE9DEFF, g_1156_global_reset);
	} else if (hw_chip_id == HAL_CHIP_ID_2952H) {
		mdelay(1500);
		pr_err("Global soft reset\n");
		writel(0x12345678, g_1156_global_reset);
		writel(0xEDCBA987, g_1156_global_reset);
	} else if (hw_chip_id == HAL_CHIP_ID_5190) {
		hi_kernel_wdt_clear();
		mdelay(3000);
	}
}

static int board_reset(struct notifier_block *nb, unsigned long action, void *data)
{
	/* board reset */
	sd511x_wdt_reset();

	return 0;
}

static int __init register_reset_init(void)
{
	int ret;

	reset_nb.notifier_call = board_reset;
	ret = register_reset_notifier(&reset_nb);
	if (ret != 0) {
		pr_err("register_reset_notifier failed\n");
		return 1;
	}
	pr_info("register_reset_notifier success\n");
	return 0;
}

static int __exit register_reset_exit(void)
{
	unregister_reset_notifier(&reset_nb);
	return 0;
}

/* wdt clear */
void hi_kernel_wdt_clear(void)
{
	unsigned long flags;

	spin_lock_irqsave(&hi_wdt_lock, flags);
	if ((hw_chip_id == HAL_CHIP_ID_1156H) || (hw_chip_id == HAL_CHIP_ID_1155H) ||
		(hw_chip_id == HAL_CHIP_ID_1156E) || (hw_chip_id == HAL_CHIP_ID_2952H)) {
		writel(HI_WDT_CLEAR_OPT1_1156, g_pui_WGT_CONFIG);
	} else if (hw_chip_id == HAL_CHIP_ID_5190) {
		hi_watchdog_reset_sd5190();
	} else {
		writel(HI_WDT_CLEAR_OPT0, g_pui_WGT_CONFIG);
		writel(HI_WDT_CLEAR_OPT1, g_pui_WGT_CONFIG);
	}

	hi_wdt_jiffies = jiffies;
	spin_unlock_irqrestore(&hi_wdt_lock, flags);
}
EXPORT_SYMBOL(hi_kernel_wdt_clear);

/* wdt dump */
static void hi_kernel_wdt_dump(void)
{
	pr_err(HI_WDT_PFX "\n\nDumping!!\n");
	/* kernel dump or something */
	dump_stack();
}

/* wdt proc call by system timer */
void hi_kernel_wdt_proc(void)
{
	return (void)hi_wdt_attr_log.wdt_proc();
}
EXPORT_SYMBOL(hi_kernel_wdt_proc);

/* wdt auto clear */
static void hi_kernel_wdt_auto_clear(struct timer_list *t)
{
	/* pet dog */
	hi_kernel_wdt_clear();

	/* update timer */
	hi_wdt_timer.expires = jiffies + (HZ * DEFAULT_AUTO_CLEAR_PERIOD);
	add_timer(&hi_wdt_timer);
}

/* wdt enable/disable */
void hi_kernel_wdt_en_set(uint32_t ui_flag)
{
	if (ui_flag > 1)
		return;

	if ((hw_chip_id == HAL_CHIP_ID_1156H) || (hw_chip_id == HAL_CHIP_ID_1155H) ||
		(hw_chip_id == HAL_CHIP_ID_1156E) || (hw_chip_id == HAL_CHIP_ID_2952H)) {
		if (ui_flag == 0) {
			WRITEL_AND((~KER_WDG_OPEN_1156), g_pui_WGT_EN);
			WRITEL_ORR(KER_WDG_CFG_1156_EN, g_1156_wdt_cfg);
		} else {
			WRITEL_ORR(KER_WDG_OPEN_1156, g_pui_WGT_EN);
			WRITEL_AND((~KER_WDG_CFG_1156_EN), g_1156_wdt_cfg);
		}
		return;
	}

	if (hw_chip_id == HAL_CHIP_ID_5190) {
		hi_watchdog_en_sd5190(ui_flag);
		return;
	}

	if (ui_flag == 0) {
		/* disable watchdog controlled by software */
		writel(gui_wdg_close_value1, g_pui_WGT_EN);
		udelay(HW_KER_WDG_DELAY);
		writel(gui_wdg_close_value2, g_pui_WGT_EN);
	} else {
		/* enable watchdog controlled by software */
		writel(gui_wdg_open_value1, g_pui_WGT_EN);
		udelay(HW_KER_WDG_DELAY);
		writel(gui_wdg_open_value2, g_pui_WGT_EN);
	}
}
EXPORT_SYMBOL(hi_kernel_wdt_en_set);

static void hi_kernel_wdt_attr_auto_mode(void)
{
	unsigned long long period;

	switch (hw_chip_id) {
	case HW_CHIP_ID_5117P_E:
	case HAL_CHIP_ID_5117PV5:
	case HW_CHIP_ID_5117V_E:
		WRITEL_ORR(WDT_RST_TIME_5117P_CFG_M, g_pui_SC_PERCTRL42);
		break;
	case HW_CHIP_ID_5182H_E:
	case HAL_CHIP_ID_5182HV5:
		WRITEL_ORR(WDT_RST_TIME_5182H_CFG_M, g_pui_SC_PERCTRL42);
		break;
	case HAL_CHIP_ID_5190:
		period = (unsigned long long)hi_wdt_attr_log.ui_period * 100000000;
		writel((uint32_t)(period & 0xffffffff), g_pui_SC_PERCTRL42);  /* 1 for 10ns */
		g_pui_SC_PERCTRL43 = ioremap(SD5190_SC_PERCTRL43, sizeof(uint32_t));
		writel((uint32_t)(period >> 32), g_pui_SC_PERCTRL43);
		iounmap(g_pui_SC_PERCTRL43);
		g_pui_SC_PERCTRL43 = NULL;
		break;
	default:
		WRITEL_ORR(WDT_RST_TIME_CFG_M, g_pui_SC_PERCTRL42);
	}
	hi_wdt_timer.expires  = jiffies + (HZ * DEFAULT_AUTO_CLEAR_PERIOD);
	add_timer(&hi_wdt_timer);
}

static void hi_kernel_wdt_attr_user_mode(void)
{
	unsigned long long period;

	uint32_t reg_val = readl(g_pui_SC_PERCTRL42);
	switch (hw_chip_id) {
	case HW_CHIP_ID_5117P_E:
	case HAL_CHIP_ID_5117PV5:
	case HW_CHIP_ID_5117V_E:
		reg_val &= ~WDT_RST_TIME_5117P_CFG_M;
		reg_val |= (2 * hi_wdt_attr_log.ui_period - 1) << WDT_RST_TIME_CFG_S;
		writel(reg_val, g_pui_SC_PERCTRL42);
		break;
	case HW_CHIP_ID_5182H_E:
	case HAL_CHIP_ID_5182HV5:
	case HAL_CHIP_ID_5182T:
		reg_val &= ~WDT_RST_TIME_5182H_CFG_M;
		reg_val |= (hi_wdt_attr_log.ui_period - 1) << WDT_RST_TIME_CFG_S_5182H;
		writel(reg_val, g_pui_SC_PERCTRL42);
		break;
	case HW_CHIP_ID_5182S_E:
	case HAL_CHIP_ID_5182SV5:
		reg_val &= ~WDT_RST_TIME_5182S_CFG_M;
		reg_val |= hi_wdt_attr_log.ui_period * 2 - 1;  //2 of 0.5s
		writel(reg_val, g_pui_SC_PERCTRL42);
		break;
	case HAL_CHIP_ID_1156H:
	case HAL_CHIP_ID_1155H:
	case HAL_CHIP_ID_1156E:
	case HAL_CHIP_ID_2952H:
		reg_val &= ~WDT_RST_TIME_1156H_CFG_M;
		reg_val = rst_time_cfg_1156(hi_wdt_attr_log.ui_period) &
			WDT_RST_TIME_1156H_CFG_M;
		writel(reg_val, g_pui_SC_PERCTRL42);
		writel(HI_WDT_CLEAR_OPT1_1156, g_pui_WGT_CONFIG);
		break;
	case HAL_CHIP_ID_5190:
		period = (unsigned long long)hi_wdt_attr_log.ui_period * 100000000;
		reg_val = (uint32_t)(period & 0xffffffff); /* 1 for 10ns */
		writel(reg_val, g_pui_SC_PERCTRL42);
		g_pui_SC_PERCTRL43 = ioremap(SD5190_SC_PERCTRL43, sizeof(uint32_t));
		writel((uint32_t)(period >> 32), g_pui_SC_PERCTRL43);
		iounmap(g_pui_SC_PERCTRL43);
		g_pui_SC_PERCTRL43 = NULL;
		break;
	default:
		reg_val &= ~WDT_RST_TIME_CFG_M;
		reg_val |= (hi_wdt_attr_log.ui_period - 1) << WDT_RST_TIME_CFG_S;
		writel(reg_val, g_pui_SC_PERCTRL42);
	}
}

/* attr set */
int hi_kernel_wdt_attr_set(struct hi_wdt_attr_s *pst_attr)
{
	unsigned long flags;

	/* args check */
	if ((pst_attr == NULL) ||
	    (pst_attr->em_mode < HI_WDT_USER_MODE_E) ||
	    (pst_attr->em_mode > HI_WDT_AUTO_MODE_E) ||
	    (pst_attr->ui_period < 1) ||
	    (pst_attr->ui_period > 300)) {
		pr_err(HI_WDT_PFX "input parameter error.\n");
		return -EINVAL;
	}

	/* clear watchdog to ensure it will restarts when set */
	hi_kernel_wdt_clear();

	/* set driver attr_log */
	hi_wdt_attr_log.em_mode		= pst_attr->em_mode;
	hi_wdt_attr_log.ui_period	= pst_attr->ui_period;
	hi_wdt_attr_log.wdt_proc	= pst_attr->wdt_proc;

	spin_lock_irqsave(&hi_wdt_lock, flags);

	if (hi_wdt_attr_log.em_mode == HI_WDT_AUTO_MODE_E)
		hi_kernel_wdt_attr_auto_mode();
	else if (hi_wdt_attr_log.em_mode == HI_WDT_USER_MODE_E)
		hi_kernel_wdt_attr_user_mode();

	spin_unlock_irqrestore(&hi_wdt_lock, flags);

	return 0;
}
EXPORT_SYMBOL(hi_kernel_wdt_attr_set);

/* attr get */
int hi_kernel_wdt_attr_get(struct hi_wdt_attr_s *pst_attr)
{
	/* arg check */
	if (pst_attr == NULL) {
		pr_err(HI_WDT_PFX "input parameter error.\n");
		return -EINVAL;
	}

	/* get driver attr_log */
	pst_attr->em_mode	= hi_wdt_attr_log.em_mode;
	pst_attr->ui_period	= hi_wdt_attr_log.ui_period;
	pst_attr->wdt_proc	= hi_wdt_attr_log.wdt_proc;

	return 0;
}
EXPORT_SYMBOL(hi_kernel_wdt_attr_get);

/* wdt init*/
static int __init hi_kernel_wdt_init(void)
{
	unsigned long long period;
	uint32_t reg_val;

	pr_info("\n [wdt] Kernel wdt init: %d\n", hw_chip_id);
	switch (hw_chip_id) {
	case HW_CHIP_ID_5115S_E:
	case HW_CHIP_ID_5115H_E:
	case HW_CHIP_ID_5115T_E:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD5115_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5115_SC_PERCTRL42, sizeof(uint32_t));
		/* wtd en config */
		WTD_EN_CFG(5115, 5115);
		break;
	case HW_CHIP_ID_5116S_E:
	case HW_CHIP_ID_5116H_E:
	case HW_CHIP_ID_5116L_E:
	case HW_CHIP_ID_5117L_E:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD5116_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5116_SC_PERCTRL42, sizeof(uint32_t));
		/* wtd en config */
		WTD_EN_CFG(5116_8, 5116);
		break;
	case HW_CHIP_ID_5116T_E:
	case HW_CHIP_ID_5116TV5_E:
	case HW_CHIP_ID_5117H_E:
	case HW_CHIP_ID_5117P_E:
	case HAL_CHIP_ID_5117PV5:
	case HW_CHIP_ID_5117V_E:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD5116_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5116T_SC_PERCTRL42, sizeof(uint32_t));
		/* wtd en config */
		WTD_EN_CFG(5116_8, 5116);
		break;
	case HW_CHIP_ID_5118_E:
	case HW_CHIP_ID_5118V2_E:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD5118_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5118_SC_PERCTRL42, sizeof(uint32_t));
		/* wtd en config */
		WTD_EN_CFG(5116_8, 5118);
		break;
	case HW_CHIP_ID_5610H_E:
	case HW_CHIP_ID_5610T_E:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD5610_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5610_SC_PERCTRL42, sizeof(uint32_t));
		/* wtd en config */
		WTD_EN_CFG(5116_8, 5610);
		break;
	case HW_CHIP_ID_5182H_E:
	case HAL_CHIP_ID_5182HV5:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD5182_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5182H_SC_PERCTRL42, sizeof(uint32_t));
		/* wtd en config */
		WTD_EN_CFG(5116_8, 5116);
		break;
	case HW_CHIP_ID_5182S_E:
	case HAL_CHIP_ID_5182SV5:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD5182_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5182S_SC_PERCTRL42, sizeof(uint32_t));
		/* wtd en config */
		WTD_EN_CFG(5182S, 5116);
		break;
	case HAL_CHIP_ID_5182T:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD5182_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5182T_SC_PERCTRL42, sizeof(uint32_t));
		/* wtd en config */
		WTD_EN_CFG(5116_8, 5116);
		break;
	case HAL_CHIP_ID_1156H:
	case HAL_CHIP_ID_1155H:
	case HAL_CHIP_ID_1156E:
	case HAL_CHIP_ID_2952H:
		/* registers remap */
		g_pui_WGT_CONFIG = ioremap(SD1156_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD1156H_SC_PERCTRL42, sizeof(uint32_t));
		g_1156_wdt_cfg = ioremap(SD1156H_WDT_CONFIG, sizeof(uint32_t));
		g_1156_global_reset = ioremap(SD1156H_GLOBAL_RST, sizeof(uint32_t));
		/* wtd en config */
		g_pui_WGT_EN = ioremap(HW_KER_WDG_ADDR_5116H, sizeof(uint32_t));
		gui_wdg_close_value1 = 0;
		gui_wdg_close_value2 = 0;
		gui_wdg_open_value1 = 1;
		gui_wdg_open_value2 = 1;
		break;
	case HAL_CHIP_ID_5190:
		g_pui_WGT_CONFIG = ioremap(SD5190_WDT_CONFIG, sizeof(uint32_t));
		g_pui_SC_PERCTRL42 = ioremap(SD5190_SC_PERCTRL42, sizeof(uint32_t));
		g_pui_WGT_EN = ioremap(SD5190_WDT_EN_REG, sizeof(uint32_t));
		break;
	default:
		pr_err("\n [wdt] chip id err: %d\n", hw_chip_id);
		return -1;
	}

	/* set drivers attr_log */
	hi_wdt_attr_log.ui_period = DEFAULT_TIMO;
	hi_wdt_attr_log.wdt_proc  = hi_kernel_wdt_dump;

	reg_val = readl(g_pui_SC_PERCTRL42);
	switch (hw_chip_id) {
	case HW_CHIP_ID_5117P_E:
	case HAL_CHIP_ID_5117PV5:
	case HW_CHIP_ID_5117V_E:
		reg_val &= ~WDT_RST_TIME_5117P_CFG_M;
		reg_val |= (2 * hi_wdt_attr_log.ui_period - 1) << WDT_RST_TIME_CFG_S;
		writel(reg_val, g_pui_SC_PERCTRL42);
		break;
	case HW_CHIP_ID_5182H_E:
	case HAL_CHIP_ID_5182HV5:
	case HAL_CHIP_ID_5182T:
		reg_val &= ~WDT_RST_TIME_5182H_CFG_M;
		reg_val |= (hi_wdt_attr_log.ui_period - 1) << WDT_RST_TIME_CFG_S_5182H;
		writel(reg_val, g_pui_SC_PERCTRL42);
		break;
	case HW_CHIP_ID_5182S_E:
	case HAL_CHIP_ID_5182SV5:
		reg_val &= ~WDT_RST_TIME_5182S_CFG_M;
		reg_val |= hi_wdt_attr_log.ui_period - 1;
		writel(reg_val, g_pui_SC_PERCTRL42);
		break;
	case HAL_CHIP_ID_1156H:
	case HAL_CHIP_ID_1155H:
	case HAL_CHIP_ID_1156E:
	case HAL_CHIP_ID_2952H:
		reg_val &= ~WDT_RST_TIME_1156H_CFG_M;
		reg_val |= rst_time_cfg_1156(hi_wdt_attr_log.ui_period) &
			WDT_RST_TIME_1156H_CFG_M;
		writel(reg_val, g_pui_SC_PERCTRL42);
		break;
	case HAL_CHIP_ID_5190:
		period = (unsigned long long)hi_wdt_attr_log.ui_period * 100000000;
		writel((uint32_t)(period & 0xffffffff), g_pui_SC_PERCTRL42);  /* 1 for 10ns */
		g_pui_SC_PERCTRL43 = ioremap(SD5190_SC_PERCTRL43, sizeof(uint32_t));
		writel((uint32_t)(period >> 32), g_pui_SC_PERCTRL43);
		iounmap(g_pui_SC_PERCTRL43);
		g_pui_SC_PERCTRL43 = NULL;

		hi_watchdog_en_sd5190(1);
		/* timeout reset time cfg will be effect only after reset watchdog */
		hi_watchdog_reset_sd5190();
		break;
	default:
		reg_val &= ~WDT_RST_TIME_CFG_M;
		reg_val |= (hi_wdt_attr_log.ui_period * 2 - 1) << WDT_RST_TIME_CFG_S;  //2 of 0.5s
		writel(reg_val, g_pui_SC_PERCTRL42);
	}

	if (hi_wdt_auto == 1) {
		pr_info(HI_WDT_PFX "Auto-Mode!\n");
		hi_wdt_attr_log.em_mode         = HI_WDT_AUTO_MODE_E;

		hi_kernel_wdt_clear();

		/* auto clear timer */
		timer_setup(&hi_wdt_timer, hi_kernel_wdt_auto_clear, 0);
		hi_wdt_timer.expires    = jiffies + (HZ * DEFAULT_AUTO_CLEAR_PERIOD);
		add_timer(&hi_wdt_timer);
	} else if (hi_wdt_auto == 0) {
		pr_info(HI_WDT_PFX "User-Mode!\n");
		hi_wdt_attr_log.em_mode = HI_WDT_USER_MODE_E;
	}

	/* register the reset hook function */
	register_reset_init();

	pr_info(HI_WDT_PFX "Init sucessfull!\n");
	return 0;
}
module_init(hi_kernel_wdt_init);

static void __exit hi_kernel_wdt_exit(void)
{
	iounmap(g_pui_WGT_CONFIG);
	iounmap(g_pui_SC_PERCTRL42);
	iounmap(g_1156_wdt_cfg);
	iounmap(g_pui_WGT_EN);
	iounmap(g_1156_global_reset);

	g_pui_WGT_CONFIG = NULL;
	g_pui_SC_PERCTRL42 = NULL;
	g_pui_WGT_EN = NULL;
	g_1156_global_reset = NULL;
	g_1156_wdt_cfg = NULL;

	register_reset_exit();
	pr_info(HI_WDT_PFX "Wdt Exit sucessfull!\n");
}
module_exit(hi_kernel_wdt_exit);

MODULE_LICENSE("GPL");
